Connectors Deep Dive
SDK + Framework Integration
This page provides a comprehensive explanation of connectors in our React marketplace.
Remember: This is our marketplace's pattern. Your marketplace can organize connectors differently (Level 1 Personalization).
What Are Connectors?
Connectors connect and integrate technologies/adapters together.
Key Principle
"A connector cannot exist without the adapters or technologies it tries to connect."
Connectors:
- β Require one or more adapters/technologies
- β Import adapter configurations
- β Extend with framework-specific features
- β Generate integration code
- β Can override tech-stack hooks (priority system for SDK-Backend type)
SDK-Backend Connectors - A Special Case
Most connectors simply bridge technologies together. But SDK-Backend Connectors are a special pattern that fundamentally changes how you build features.
Regular Connectors (Most Common)
Purpose: Connect and integrate technologies.
Examples:
connectors/database/drizzle-nextjs- Connects Drizzle ORM to Next.jsconnectors/deployment/docker-nextjs- Integrates Docker with Next.jsconnectors/monitoring/sentry-nextjs- Integrates Sentry with Next.jsconnectors/database/drizzle-postgres-docker- Connects Drizzle + Postgres + Dockerconnectors/infrastructure/tanstack-query-nextjs- Sets up TanStack Query for Next.js
Characteristics:
- Bridge adapters/technologies
- Provide wiring, configuration, infrastructure
- Various roles/patterns depending on what they connect
- Do NOT replace feature backends
What they typically provide:
{
"provides": [
"technology-wiring",
"framework-integration",
"configuration"
]
}SDK-Backend Connectors (Special Case) π
Purpose: REPLACE the entire backend layer for a feature using SDK capabilities.
This is a fundamentally different pattern!
Examples (Only These):
connectors/auth/better-auth-nextjs- Complete auth backend via Better Auth SDKconnectors/payment/stripe-nextjs-drizzle- Complete payment backend via Stripe SDK
Characteristics:
role: "sdk-backend-connector"pattern: "sdk-driven"- Provide complete backend functionality
- Provide SDK-native hooks
- Eliminate the need for
features/[name]/backend/
What they MUST provide:
{
"provides": [
"feature-backend-complete", // β Backend replacement!
"feature-sdk-native-hooks", // β SDK hooks (e.g., authClient.useSession())
"feature-api-routes", // β API endpoints
"feature-middleware" // β Optional middleware
],
"role": "sdk-backend-connector",
"pattern": "sdk-driven"
}π Key Insight: When you use an SDK-Backend Connector, you DON'T create a backend/ folder in your feature. The connector IS the backend!
Why so few? Most SDKs don't provide complete backend functionality. Only SDKs like Better Auth (full auth) or Stripe (full payments) qualify.
Decision Tree
What does this connector do?
β
ββ Bridges/integrates technologies
β ββ Regular Connector
β Examples: drizzle-nextjs, docker-nextjs, sentry-nextjs
β
ββ Provides COMPLETE backend for a feature via SDK
ββ SDK-Backend Connector
Examples: better-auth-nextjs, stripe-nextjs-drizzle
Must have: "feature-backend-complete" in providesWhy Do We Need Connectors?
The Problem Without Connectors
Without connectors, adapters would need framework-specific code:
// β BAD: Adapter with framework coupling
// adapters/auth/better-auth/config.ts
import { nextCookies } from 'better-auth/next-js'; // β Next.js import!
export const auth = betterAuth({
plugins: [nextCookies()], // β Framework-specific!
});Problems:
- π΄ Adapter becomes framework-specific
- π΄ Can't reuse with Remix, Astro, etc.
- π΄ Violates framework-agnostic principle
The Solution: Connectors
With connectors, adapters stay universal, connectors add framework integration:
// β
GOOD: Universal adapter
// adapters/auth/better-auth/config.ts
export const auth = betterAuth({
database: drizzleAdapter(db),
emailAndPassword: { enabled: true },
// No framework-specific code!
});
// β
GOOD: Next.js connector
// connectors/auth/better-auth-nextjs/config.ts
import { auth as baseAuth } from '@/lib/auth/better-auth'; // Import adapter
import { nextCookies } from 'better-auth/next-js';
export const auth = betterAuth({
...baseAuth.options, // β Use adapter config
plugins: [nextCookies()], // β Add Next.js specific
});Benefits:
- β Adapter remains framework-agnostic
- β Connector adds framework integration
- β
Can have
better-auth-remix,better-auth-astro, etc. - β Single adapter, multiple connectors
The Adapter β Connector Pattern
The Flow
1. Adapter (Universal SDK Config)
β imports
2. Connector (Framework Integration)
β provides hooks to
3. Feature (Business Logic)Real Example: Auth
Step 1: Adapter (Universal)
// adapters/auth/better-auth/config.ts
export const auth = betterAuth({
database: drizzleAdapter(db),
emailAndPassword: { enabled: true },
session: { expiresIn: 60 * 60 * 24 * 7 },
});Deployed to: src/lib/auth/better-auth-config.ts
Framework-agnostic: β
Step 2: Connector (Next.js)
// connectors/auth/better-auth-nextjs/config.ts
import { auth as baseAuth } from '@/lib/auth/better-auth-config';
import { nextCookies } from 'better-auth/next-js';
export const auth = betterAuth({
...baseAuth.options, // β Import adapter
plugins: [
nextCookies(), // β Add Next.js cookies plugin
...baseAuth.options.plugins || [],
],
});Deployed to: src/lib/auth/config.ts
Next.js-specific: β
Step 3: Also Generates
- API routes:
/api/auth/[...all]/route.ts - Middleware:
middleware.ts - Client hooks:
src/lib/auth/client.ts - Native hooks:
src/lib/auth/hooks.ts(priority 2)
Connector Structure
Minimal Connector
connectors/[category]/[name]/
βββ connector.json (Metadata - requires adapters!)
βββ blueprint.ts (Generation logic)
βββ templates/ (Framework-specific templates)
β βββ config.ts.tpl
β βββ api-routes.ts.tpl
β βββ middleware.ts.tpl
β βββ hooks.ts.tpl
βββ README.md (Documentation)Example: Better Auth Next.js Connector
connectors/auth/better-auth-nextjs/
βββ connector.json
βββ blueprint.ts
βββ templates/
β βββ config.ts.tpl (Extends adapter config)
β βββ api-auth-route.ts.tpl (Next.js API route)
β βββ middleware.ts.tpl (Next.js middleware)
β βββ client.ts.tpl (Auth client)
β βββ hooks.ts.tpl (SDK-native hooks, priority 2)
βββ README.mdConnector Metadata (connector.json)
{
"name": "Better Auth Next.js Connector",
"id": "connectors/auth/better-auth-nextjs",
"type": "connector",
"category": "auth",
"version": "1.0.0",
"description": "Integrates Better Auth with Next.js",
"requires": [
"adapters/auth/better-auth", // β Must have adapter!
"framework/nextjs" // β Must have framework!
],
"provides": ["auth-nextjs", "session-middleware"],
"capabilities": {
"provides": ["auth-integration", "api-routes", "middleware"],
"requires": ["auth", "nextjs"]
}
}Key Fields:
requires: CRITICAL! Lists required adapters and frameworkcategory: Same as adapter (auth, payment, ai, etc.)provides: What this connector enablescapabilities.requires: What must exist before this runs
Category-First Organization
Why Category-First?
Our connectors are organized by business domain:
connectors/
βββ auth/ (Authentication)
β βββ better-auth-nextjs/
βββ payment/ (Payments)
β βββ stripe-nextjs-drizzle/
βββ ai/ (AI Integration)
β βββ vercel-ai-nextjs/
βββ email/ (Email Services)
β βββ resend-nextjs/
βββ database/ (Database)
β βββ drizzle-neon/
βββ infrastructure/ (Core Infrastructure)
β βββ tanstack-query-nextjs/
β βββ zustand-nextjs/
β βββ rhf-zod-shadcn/
βββ monitoring/ (Observability)
β βββ sentry-nextjs/
βββ testing/ (Testing)
β βββ vitest-nextjs/
βββ deployment/ (Deployment)
βββ docker-nextjs/Why this structure?
- β
Easy discovery ("I need auth for Next.js" β
connectors/auth/) - β Scalable (add more auth connectors as needed)
- β Clear purpose (folder name = business domain)
- β Groups related connectors
The Backend Overwrites Hooks Pattern
What Is It?
Connectors can provide SDK-native hooks that override generic tech-stack hooks using a priority system.
The Priority System
Priority 1: Tech-Stack (Generic Fallback)
// features/auth/tech-stack/hooks.ts
export function useSession() {
return useQuery({
queryKey: ['session'],
queryFn: async () => {
const res = await fetch('/api/auth/session');
return res.json();
},
});
}Deployed to: src/lib/auth/hooks.ts (priority: 1)
Priority 2: Connector (SDK-Native - OVERWRITES!)
// connectors/auth/better-auth-nextjs/hooks.ts
export { useSession, signIn, signOut } from '@/lib/auth/client';Deployed to: src/lib/auth/hooks.ts (priority: 2) β WINS!
How It Works
1. Tech-stack provides generic hooks:
// features/auth/tech-stack/blueprint.ts
{
action: 'deploy_template',
template: 'hooks.ts.tpl',
target: '{{paths.auth_config}}/hooks.ts',
priority: 1, // β Generic fallback
}2. Connector provides SDK-native hooks:
// connectors/auth/better-auth-nextjs/blueprint.ts
{
action: 'deploy_template',
template: 'hooks.ts.tpl',
target: '{{paths.auth_config}}/hooks.ts',
priority: 2, // β Overwrites tech-stack!
}3. Frontend imports from unified path:
// Frontend component
import { useSession } from '@/lib/auth'; // Gets Better Auth native hook!Why This Pattern?
Progressive Enhancement:
- Start with generic hooks (work with any backend)
- Connector adds optimized SDK-native hooks
- Frontend code doesn't change
SDK Advantages:
// Generic hook (priority 1):
useQuery({ queryFn: () => fetch('/api/session') })
// Better Auth native hook (priority 2):
useSession()
β
Built-in SSR support
β
Automatic revalidation
β
Optimized caching
β
Type-safe
β
Real-time updatesTech-Stack Remains Agnostic:
- Tech-stack doesn't know about Better Auth
- Connector adds Better Auth integration
- Can swap auth providers without touching tech-stack
Real Examples
Example 1: Better Auth Next.js Connector
What it does:
1. Imports adapter config:
// templates/config.ts.tpl
import { auth as baseAuth } from '@/lib/auth/better-auth-config';
export const auth = betterAuth({
...baseAuth.options,
plugins: [nextCookies()],
});2. Generates API routes:
// templates/api-auth-route.ts.tpl
import { auth } from '@/lib/auth/config';
import { toNextJsHandler } from 'better-auth/next-js';
export const { GET, POST } = toNextJsHandler(auth);Deployed to: src/app/api/auth/[...all]/route.ts
3. Generates middleware:
// templates/middleware.ts.tpl
import { auth } from '@/lib/auth/config';
import { NextResponse } from 'next/server';
export async function middleware(request) {
const session = await auth.api.getSession({
headers: request.headers,
});
if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}Deployed to: middleware.ts
4. Provides SDK-native hooks:
// templates/hooks.ts.tpl
export {
useSession,
signIn,
signOut,
signUp,
} from '@/lib/auth/client';Deployed to: src/lib/auth/hooks.ts (priority 2)
Example 2: Stripe Next.js Drizzle Connector
What it does:
1. Imports from both adapters:
// templates/server.ts.tpl
import { stripe } from '@/lib/payment/stripe'; // From adapter
import { db } from '@/db/client'; // From database adapter
export async function createCheckout(userId: string) {
return stripe.checkout.sessions.create({
customer: userId,
// ...
});
}2. Generates webhook handler:
// templates/webhook-route.ts.tpl
import { stripe } from '@/lib/payment/stripe';
import { db } from '@/db/client';
import { headers } from 'next/headers';
export async function POST(request: Request) {
const body = await request.text();
const signature = headers().get('stripe-signature')!;
const event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
// Handle events and update database
await handleStripeEvent(event, db);
return new Response('OK', { status: 200 });
}Deployed to: src/app/api/webhooks/stripe/route.ts
3. Generates checkout API:
// templates/checkout-route.ts.tpl
export async function POST(request: Request) {
const { priceId } = await request.json();
const session = await createCheckout(priceId);
return Response.json({ url: session.url });
}Example 3: Vercel AI Next.js Connector
What it does:
1. Imports adapter config:
// templates/hooks.ts.tpl
export { useChat, useCompletion } from 'ai/react';2. Generates streaming API route:
// templates/api-chat-route.ts.tpl
import { openai } from '@/lib/ai/config';
import { streamText } from 'ai';
export async function POST(request: Request) {
const { messages } = await request.json();
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
});
return result.toDataStreamResponse();
}Deployed to: src/app/api/chat/route.ts
When to Create a Connector
β Create a Connector When:
1. Bridging SDK + Framework
// β
Good: Adapter + Framework integration
connectors/auth/better-auth-nextjs/
β Requires: adapters/auth/better-auth
β Requires: framework/nextjs
β Provides: Next.js API routes, middleware2. Framework-Specific Integration Required
// β
Good: Sentry needs Next.js config
connectors/monitoring/sentry-nextjs/
β Next.js specific instrumentation
β Error boundary setup
β API route integration3. SDK Has Native Framework Support
// β
Good: Better Auth has Next.js plugins
connectors/auth/better-auth-nextjs/
β nextCookies() plugin
β toNextJsHandler() helper
β Next.js optimized hooks4. Generating Framework Boilerplate
// β
Good: TanStack Query needs SSR setup
connectors/infrastructure/tanstack-query-nextjs/
β Query client provider
β SSR hydration
β Next.js app directory setupβ Don't Create a Connector When:
1. Adapter Is Already Framework-Specific
// β Bad: Framework adapter doesn't need connector
adapters/framework/nextjs/
β Already Next.js specific
β No connector needed2. No Framework Integration Needed
// β Bad: Just install directly
connectors/utils/lodash-nextjs/
β lodash doesn't need Next.js integration
β Just install package directly3. Feature Backend Handles It
// β Bad: Custom logic = feature backend
connectors/teams/custom-teams-nextjs/
β Custom business logic should be in:
β features/teams/backend/nextjs/Best Practices
1. Always Require Adapters
β Good:
{
"requires": [
"adapters/auth/better-auth", // β Required!
"framework/nextjs"
]
}β Bad:
{
"requires": [
"framework/nextjs" // β Missing adapter!
]
}2. Import From Adapters
β Good:
// Import adapter config
import { auth as baseAuth } from '@/lib/auth/better-auth-config';
export const auth = betterAuth({
...baseAuth.options, // β Use adapter config
plugins: [nextCookies()],
});β Bad:
// Create new instance (duplication!)
export const auth = betterAuth({
database: { /* duplicate config */ }, // β
plugins: [nextCookies()],
});3. Use Priority System Appropriately
β Good:
{
action: 'deploy_template',
template: 'hooks.ts.tpl',
target: '{{paths.auth_config}}/hooks.ts',
priority: 2, // β Overwrites tech-stack (priority 1)
}4. Organize by Category
β Good:
connectors/[category]/[name]/
connectors/auth/better-auth-nextjs/β Bad:
connectors/better-auth-nextjs/ // β No categoryConnector Patterns
Pattern 1: API Route Generator
Purpose: Generate framework-specific API routes
// connectors/auth/better-auth-nextjs/templates/api-route.ts.tpl
import { auth } from '@/lib/auth/config';
import { toNextJsHandler } from 'better-auth/next-js';
export const { GET, POST } = toNextJsHandler(auth);Pattern 2: Middleware Generator
Purpose: Generate framework middleware
// connectors/auth/better-auth-nextjs/templates/middleware.ts.tpl
export async function middleware(request) {
const session = await auth.api.getSession({
headers: request.headers,
});
// ... middleware logic
}Pattern 3: Hook Overwriter
Purpose: Provide SDK-native hooks (priority 2)
// connectors/auth/better-auth-nextjs/templates/hooks.ts.tpl
export { useSession, signIn, signOut } from '@/lib/auth/client';
// Deployed with priority: 2 (overwrites tech-stack)Pattern 4: Provider Generator
Purpose: Generate framework providers
// connectors/infrastructure/tanstack-query-nextjs/templates/provider.tsx.tpl
'use client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';
export function QueryProvider({ children }) {
const [queryClient] = useState(() => new QueryClient());
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
}Summary
Key Takeaways
-
Connectors bridge adapters + frameworks
- Always require one or more adapters
- Add framework-specific integration
-
Connectors import from adapters
- Extend adapter configuration
- Add framework-specific plugins/features
-
Connectors can override hooks
- Use priority system (2 > 1)
- Provide SDK-native hooks
-
Connectors are organized by category
- Easy discovery
- Scalable structure
Decision Tree
Do I need to integrate SDK + Framework?
ββ YES β Does adapter exist for SDK?
β ββ YES β β
CREATE CONNECTOR
β ββ NO β β CREATE ADAPTER FIRST, then connector
β
ββ NO β Is this just framework setup?
ββ YES β β Use framework adapter directly
ββ NO β β Feature backend or not neededThe Golden Rule
"A connector cannot exist without the adapters it tries to connect."
Always:
- β Check if adapter exists
- β
Declare adapter in
requiresfield - β Import from adapter (don't duplicate)
- β Add framework-specific features
Next Steps
- Adapters Deep Dive β - Learn about adapters
- Features Deep Dive β - Learn about features
- Architecture Overview β - High-level concepts
- Contributing β - Build your own connector
Remember: Connectors bridge universal adapters with specific frameworks. They cannot exist without the adapters they connect!