Claude + Supabase Edge Functions: Real-Time AI for Full-Stack Apps
Integrate Claude AI into Supabase Edge Functions for lightning-fast, serverless processing of real-time data. Build intelligent full-stack apps with instant insights and automations right at the edge.
Introduction
Imagine a full-stack app where user inputs trigger AI analysis in milliseconds—no separate servers, no cold starts, just seamless intelligence powered by Claude and Supabase. Supabase Edge Functions, running on Deno at the edge, combined with Anthropic's Claude API, enable serverless AI that processes database events instantly. This setup is perfect for real-time apps like chatbots, support ticketing, or collaborative tools needing on-the-fly summarization, sentiment analysis, or auto-responses.
In this guide, we'll build a real-time support ticket system. Users submit tickets via a web app; a database trigger fires an Edge Function that calls Claude to classify urgency, detect sentiment, and generate a suggested response—all streamed back in real-time to the frontend.
Why this stack?
- Low latency: Edge Functions execute near users (global CDN).
- Serverless scaling: No infra management.
- Claude's strengths: Superior reasoning, tool use, and context handling (e.g., Claude 3.5 Sonnet excels at nuanced classification).
- Supabase Realtime: Broadcasts AI outputs instantly via WebSockets.
We'll cover setup, code, deployment, and optimizations. Let's dive in.
Prerequisites
Before starting:
- Supabase account (free tier works).
- Anthropic API key (Claude API access).
- Supabase CLI installed (
npm install -g supabase). - Node.js (for frontend dev).
- Basic familiarity with JavaScript and SQL.
Pro Tip: Use Claude 3.5 Sonnet (claude-3-5-sonnet-20240620) for best speed/accuracy balance in real-time scenarios.
Step 1: Set Up Your Supabase Project
-
Log in to Supabase Dashboard and create a new project (e.g.,
claude-support-tickets). -
Create a
ticketstable for storing submissions:
-- Run in Supabase SQL Editor
CREATE TABLE tickets (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
created_at TIMESTAMPTZ DEFAULT NOW(),
user_id UUID REFERENCES auth.users(id),
message TEXT NOT NULL,
urgency TEXT, -- AI-classified: low/medium/high
sentiment TEXT, -- AI-classified: positive/neutral/negative
suggested_response TEXT, -- AI-generated
status TEXT DEFAULT 'open'
);
-- Enable RLS
ALTER TABLE tickets ENABLE ROW LEVEL SECURITY;
-- Policy for authenticated inserts
CREATE POLICY "Users can insert tickets" ON tickets
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Policy for select (for realtime)
CREATE POLICY "Users can view own tickets" ON tickets
FOR SELECT USING (auth.uid() = user_id);
- Enable Realtime on the
ticketstable:- Dashboard > Database > Replication > Toggle
tickets.
- Dashboard > Database > Replication > Toggle
Your DB is now ready for real-time AI magic.
Step 2: Secure Your Claude API Key
- In Supabase Dashboard > Edge Functions > Secrets, set:
(Or via CLI:supabase secrets set ANTHROPIC_API_KEY=sk-ant-...supabase secrets set --env-file ./supabase/.env)
This keeps your key server-side only.
Step 3: Create the Edge Function for Claude Processing
Edge Functions are Deno scripts invoked via HTTPS. We'll make process-ticket call Claude to analyze and enrich tickets.
-
Init functions locally:
supabase init supabase functions new process-ticket -
Edit
supabase/functions/process-ticket/index.ts:
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
const supabaseClient = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '',
);
const { ticket_id } = await req.json();
// Fetch ticket
const { data: ticket } = await supabaseClient
.from('tickets')
.select('*')
.eq('id', ticket_id)
.single();
if (!ticket) {
throw new Error('Ticket not found');
}
// Claude prompt engineering: Structured output for reliability
const prompt = `
Analyze this support ticket message: "${ticket.message}"
Classify:
- urgency: low | medium | high
- sentiment: positive | neutral | negative
Generate a helpful suggested response (under 200 words).
Respond ONLY in JSON: {"urgency": "...", "sentiment": "...", "suggested_response": "..."}
`;
const claudeResponse = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': Deno.env.get('ANTHROPIC_API_KEY'),
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20240620',
max_tokens: 500,
temperature: 0.2,
messages: [{ role: 'user', content: prompt }],
}),
});
const claudeData = await claudeResponse.json();
const analysis = JSON.parse(claudeData.content[0].text);
// Update ticket with AI results
const { error } = await supabaseClient
.from('tickets')
.update({
urgency: analysis.urgency,
sentiment: analysis.sentiment,
suggested_response: analysis.suggested_response,
})
.eq('id', ticket_id);
if (error) throw error;
return new Response(
JSON.stringify({ success: true, analysis }),
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } },
);
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{ status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } },
);
}
});
Key Claude Tips:
- JSON mode: Force structured output with "Respond ONLY in JSON".
- Low temperature: Ensures consistent classifications.
- Context window: Claude handles long messages well (200K tokens).
- Deploy:
supabase functions deploy process-ticket
Your function is live at https://<project>.supabase.co/functions/v1/process-ticket.
Step 4: Wire Up Database Triggers for Instant Invocation
To auto-trigger on inserts, use Postgres http extension to call the Edge Function server-side.
-
Enable
httpextension (Dashboard > Database > Extensions):CREATE EXTENSION IF NOT EXISTS http; -
Create trigger function:
CREATE OR REPLACE FUNCTION handle_new_ticket() RETURNS TRIGGER AS $$ DECLARE function_url TEXT := 'https://<your-project-ref>.supabase.co/functions/v1/process-ticket'; resp JSON; BEGIN SELECT * INTO resp FROM http_post( function_url, json_build_object('ticket_id', NEW.id)::text, json_build_object( 'Authorization', 'Bearer ' || current_setting('request.access_token') ), 'application/json' ); RETURN NEW; EXCEPTION WHEN OTHERS THEN -- Log error, don't fail insert RETURN NEW; END; $$ LANGUAGE plpgsql; -
Attach trigger:
CREATE TRIGGER on_ticket_insert AFTER INSERT ON tickets FOR EACH ROW EXECUTE FUNCTION handle_new_ticket();
Now, every ticket insert auto-invokes Claude via Edge Function—results update the row instantly!
Step 5: Build the Real-Time Frontend
Create a simple React app with Supabase client for inserts and subscriptions.
-
Init app:
npx create-react-app claude-supabase-tickets && cd claude-supabase-tickets -
Install deps:
npm i @supabase/supabase-js -
src/App.js:
import { useState, useEffect } from 'react';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient('https://<project>.supabase.co', 'your-anon-key');
function App() {
const [tickets, setTickets] = useState([]);
const [message, setMessage] = useState('');
useEffect(() => {
// Realtime subscription
const channel = supabase
.channel('tickets')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'tickets' },
(payload) => {
setTickets((prev) => {
if (payload.eventType === 'INSERT') {
return [payload.new, ...prev];
}
// Handle updates
return prev.map((t) =>
t.id === payload.new.id ? payload.new : t
);
});
}
)
.subscribe();
// Initial load
fetchTickets();
return () => { supabase.removeChannel(channel); };
}, []);
const fetchTickets = async () => {
const { data } = await supabase.from('tickets').select('*');
setTickets(data || []);
};
const submitTicket = async () => {
const { data: { user } } = await supabase.auth.getUser();
await supabase.from('tickets').insert({
user_id: user.id,
message,
});
setMessage('');
};
return (
<div>
<h1>AI-Powered Support Tickets</h1>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Describe your issue..."
/>
<button onClick={submitTicket}>Submit</button>
<ul>
{tickets.map((ticket) => (
<li key={ticket.id}>
<strong>{ticket.message}</strong><br/>
Urgency: {ticket.urgency || 'Processing...'}
| Sentiment: {ticket.sentiment || '...'}
<br/><em>Suggested: {ticket.suggested_response || '...'}</em>
</li>
))}
</ul>
</div>
);
}
export default App;
-
Add auth (Supabase > Auth > Settings > Enable providers). Wrap in auth check.
-
Run:
npm start. Submit a ticket—watch Claude process it in real-time!
Step 6: Deploy, Monitor, and Scale
- Frontend: Deploy to Vercel/Netlify, set env vars.
- Monitoring: Supabase Logs for functions; Anthropic Console for API usage.
- Costs: Edge Functions ~$0.0001/invocation; Claude ~$3/million tokens.
Optimizations:
- Streaming: Modify Claude call with
stream: true, pipe to client via ReadableStream. - Batch: Queue multiple events for cost savings (use Supabase pg_cron).
- Caching: Redis for repeated analyses.
- Prompt Tuning: Test with Claude's XML tags for complex outputs:
<urgency>high</urgency>.
Advanced: Multi-Modal AI
Extend to images: Upload via Supabase Storage, base64 to Claude Vision (e.g., analyze ticket screenshots).
// In prompt
model: 'claude-3-5-sonnet-20240620',
messages: [{
role: 'user',
content: [{ type: 'text', text: prompt }, { type: 'image', source: { url: imageUrl } }]
}]
Conclusion
You've built a production-ready real-time AI app with Claude + Supabase Edge Functions. This pattern scales to HR onboarding (auto-resume screening), marketing (sentiment on leads), or engineering (code review bots). Experiment with Claude's tools for DB queries or MCP servers for extended capabilities.
Fork the code, share your builds on Claude Directory forums! Questions? Drop in comments.
Word count: ~1450
Comments
More Blog
View allBuilding Voice Agents with Claude API and ElevenLabs: Conversational AI Guide
Build natural voice agents combining Claude API's superior reasoning with ElevenLabs' lifelike TTS. This end-to-end guide creates a conversational web app with STT, AI chat, and speech synthesis.
Claude vs Mistral Large 2: 2025 Data Analysis Benchmarks and Use Cases
As data volumes explode in 2025, choosing between Claude's reasoning depth and Mistral Large 2's efficiency is critical. We benchmark SQL generation, visualizations, and large datasets to reveal the w
Claude Enterprise for Cybersecurity: Threat Modeling and Incident Response
In the high-stakes world of cybersecurity, rapid threat modeling and incident response can mean the difference between containment and catastrophe. Discover how Claude Enterprise empowers security tea
Claude Code in VS Code: Custom Commands for Refactoring Large Codebases
Refactoring sprawling codebases manually? Harness Claude Code's power in VS Code with custom commands to automate AI-driven refactors across TypeScript and Python projects—saving hours of drudgery.
Claude SDK Rust for Blockchain: Smart Contract Auditing Agents
Build blazing-fast smart contract auditing agents in Rust using the Claude SDK. Harness Claude's reasoning to scan Solidity code for vulnerabilities like reentrancy and overflows.
Advanced Claude Artifacts: Collaborative Editing in Multi-User Sessions
Elevate team productivity with Claude Artifacts in multi-user projects—enable real-time iterative editing for code reviews and docs without leaving the interface.