Edge Functions Deployment
Deploy Flow
Manual Deployment
# Deploy single function
supabase functions deploy my-function
# Deploy all functions
supabase functions deploy
# Deploy with specific project
supabase functions deploy --project-ref <project-id>
Deployment Process
┌─────────────────────────────────────────────────────────────┐
│ DEPLOYMENT FLOW │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. supabase functions deploy │
│ │ │
│ ▼ │
│ 2. Bundle TypeScript/JavaScript │
│ │ │
│ ▼ │
│ 3. Upload to Supabase │
│ │ │
│ ▼ │
│ 4. Deploy to global edge network │
│ │ │
│ ▼ │
│ 5. Function available at: │
│ https://project-ref.supabase.co/functions/v1/name │
│ │
└─────────────────────────────────────────────────────────────┘
CI/CD Deployment
GitHub Actions
# .github/workflows/deploy-functions.yml
name: Deploy Edge Functions
on:
push:
branches: [main]
paths:
- 'supabase/functions/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
with:
version: latest
- name: Deploy Functions
run: |
supabase functions deploy --project-ref ${{ vars.SUPABASE_PROJECT_REF }}
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
With Secrets Management
name: Deploy Functions with Secrets
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
- name: Link Project
run: supabase link --project-ref ${{ vars.SUPABASE_PROJECT_REF }}
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
- name: Set Secrets
run: |
supabase secrets set \
STRIPE_SECRET_KEY=${{ secrets.STRIPE_SECRET_KEY }} \
SENDGRID_API_KEY=${{ secrets.SENDGRID_API_KEY }}
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
- name: Deploy Functions
run: supabase functions deploy
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
Managing Secrets
Set Secrets
# Set single secret
supabase secrets set MY_API_KEY=sk_live_xxxxx
# Set multiple secrets
supabase secrets set \
STRIPE_KEY=sk_live_xxx \
SENDGRID_KEY=SG.xxx \
WEBHOOK_SECRET=whsec_xxx
# List current secrets (names only, not values)
supabase secrets list
# Unset secret
supabase secrets unset MY_API_KEY
Local Development
# Create local env file
# supabase/functions/.env.local
STRIPE_KEY=sk_test_xxx
SENDGRID_KEY=SG.xxx_test
# Serve with env file
supabase functions serve --env-file supabase/functions/.env.local
Function Versioning
Deployment Strategy
┌─────────────────────────────────────────────────────────────┐
│ VERSIONING STRATEGY │
├─────────────────────────────────────────────────────────────┤
│ │
│ Option 1: Overwrite (Default) │
│ - Each deploy replaces previous version │
│ - Simple, no version management │
│ │
│ Option 2: Versioned Functions │
│ - my-function-v1, my-function-v2 │
│ - Client specifies version │
│ - More complex, but safer rollbacks │
│ │
│ Recommendation: Use Option 1 + Git tags for rollback │
│ │
└─────────────────────────────────────────────────────────────┘
Rollback Strategy
# Rollback using git
git checkout <previous-commit> -- supabase/functions/my-function/
supabase functions deploy my-function
# Or redeploy from tag
git checkout v1.0.0
supabase functions deploy my-function
Monitoring & Logs
View Logs
# Stream logs
supabase functions logs my-function
# Tail logs
supabase functions logs my-function --follow
# Filter by time
supabase functions logs my-function --since 1h
Dashboard Logs
Supabase Dashboard
└── Edge Functions
└── Select function
└── Logs tab
- Invocations
- Errors
- Duration
Error Handling Best Practices
Structured Logging
serve(async (req: Request) => {
const requestId = crypto.randomUUID();
console.log(JSON.stringify({
level: 'info',
requestId,
message: 'Function invoked',
method: req.method,
url: req.url,
}));
try {
const result = await processRequest(req);
console.log(JSON.stringify({
level: 'info',
requestId,
message: 'Request processed successfully',
}));
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error(JSON.stringify({
level: 'error',
requestId,
message: 'Request failed',
error: error.message,
stack: error.stack,
}));
return new Response(
JSON.stringify({ error: 'Internal server error', requestId }),
{ status: 500, headers: { 'Content-Type': 'application/json' } }
);
}
});
Testing Before Deploy
Local Testing
# Start local Supabase
supabase start
# Serve functions locally
supabase functions serve
# Test with curl
curl -X POST http://localhost:54321/functions/v1/my-function \
-H "Authorization: Bearer $ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "test"}'
Integration Tests
// tests/functions.test.ts
import { createClient } from '@supabase/supabase-js';
describe('Edge Functions', () => {
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!
);
test('my-function returns expected result', async () => {
const { data, error } = await supabase.functions.invoke('my-function', {
body: { name: 'test' },
});
expect(error).toBeNull();
expect(data.message).toBe('Hello test!');
});
});
Tổng kết
Deployment Commands
# Deploy
supabase functions deploy [name]
# Secrets
supabase secrets set KEY=value
supabase secrets list
# Logs
supabase functions logs [name] --follow
CI/CD Checklist
- [ ] Access token in GitHub secrets
- [ ] Project ref in GitHub variables
- [ ] Deploy on push to main
- [ ] Set function secrets in CI
- [ ] Monitor logs after deploy
Best Practices
✅ Test locally before deploy
✅ Use environment-specific secrets
✅ Monitor logs after deployment
✅ Tag releases for rollback
✅ Structured logging
Q&A
- Có CI/CD pipeline cho functions chưa?
- Cần monitoring gì thêm?
- Rollback strategy như thế nào?