Low-Code & Internal Tool Platforms
Platform Selection
| Platform |
Best For |
Pricing Model |
| Retool |
Internal tools, admin panels |
Per-user |
| Supabase |
Backend-as-a-service, auth, DB |
Usage-based |
| Appsmith |
Internal tools (open source) |
Self-host free |
| Tooljet |
Internal tools (open source) |
Self-host free |
| n8n |
Workflow automation (open source) |
Self-host free |
| Zapier |
SaaS-to-SaaS integrations |
Per-task |
Supabase
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
// Auth
const { data: { user } } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure-password',
});
// Database (auto-generated REST API from Postgres)
const { data, error } = await supabase
.from('posts')
.select('*, author:users(name)')
.eq('published', true)
.order('created_at', { ascending: false })
.limit(10);
// Real-time subscriptions
supabase.channel('posts')
.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'posts' },
(payload) => console.log('New post:', payload.new))
.subscribe();
// Row Level Security (RLS)
// CREATE POLICY "Users can only see own posts"
// ON posts FOR SELECT
// USING (auth.uid() = user_id);
// Storage
const { data: upload } = await supabase.storage
.from('avatars')
.upload('user_123/avatar.png', file);
// Edge Functions (Deno)
// supabase/functions/hello/index.ts
Deno.serve(async (req) => {
return new Response(JSON.stringify({ message: 'Hello!' }));
});
Retool
// Retool query (SQL)
SELECT * FROM orders
WHERE status = {{ statusDropdown.value }}
AND created_at >= {{ dateRange.start }}
ORDER BY created_at DESC
LIMIT {{ pagination.pageSize }}
OFFSET {{ (pagination.page - 1) * pagination.pageSize }}
// Retool transformer
const enriched = data.map(row => ({
...row,
total_formatted: `$${row.total.toFixed(2)}`,
status_color: row.status === 'paid' ? 'green' : 'red',
}));
return enriched;
n8n Workflow Automation
{
"nodes": [
{ "type": "n8n-nodes-base.webhook", "name": "Webhook Trigger" },
{ "type": "n8n-nodes-base.httpRequest", "name": "Fetch Data" },
{ "type": "n8n-nodes-base.if", "name": "Check Condition" },
{ "type": "n8n-nodes-base.slack", "name": "Send Notification" }
]
}
Integration Patterns
- Custom code escape hatches: When low-code hits limits, embed custom JS/Python
- API-first backend: Use Supabase/Firebase as backend, custom frontend
- Hybrid architecture: Low-code for admin panels, custom code for customer-facing
- Data sync: Webhook-triggered n8n/Zapier workflows between SaaS tools
- Self-hosting: Prefer Appsmith/Tooljet/n8n for data sovereignty requirements
1---2name: low-code-platforms3description: Low-code and internal tool platforms including Retool, Supabase, Appsmith, Tooljet, n8n, and Zapier. Use when building admin panels, internal tools, workflow automations, or integrating low-code platforms with custom code.4---5
6# Low-Code & Internal Tool Platforms
7
8## Platform Selection
9
10| Platform | Best For | Pricing Model |
11|----------|----------|---------------|
12| **Retool** | Internal tools, admin panels | Per-user |
13| **Supabase** | Backend-as-a-service, auth, DB | Usage-based |
14| **Appsmith** | Internal tools (open source) | Self-host free |
15| **Tooljet** | Internal tools (open source) | Self-host free |
16| **n8n** | Workflow automation (open source) | Self-host free |
17| **Zapier** | SaaS-to-SaaS integrations | Per-task |
18
19## Supabase
20
21```typescript
22import { createClient } from '@supabase/supabase-js';
23
24const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
25
26// Auth
27const { data: { user } } = await supabase.auth.signUp({
28 email: 'user@example.com',
29 password: 'secure-password',
30});
31
32// Database (auto-generated REST API from Postgres)
33const { data, error } = await supabase
34 .from('posts')
35 .select('*, author:users(name)')
36 .eq('published', true)
37 .order('created_at', { ascending: false })
38 .limit(10);
39
40// Real-time subscriptions
41supabase.channel('posts')
42 .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'posts' },
43 (payload) => console.log('New post:', payload.new))
44 .subscribe();
45
46// Row Level Security (RLS)
47// CREATE POLICY "Users can only see own posts"
48// ON posts FOR SELECT
49// USING (auth.uid() = user_id);
50
51// Storage
52const { data: upload } = await supabase.storage
53 .from('avatars')
54 .upload('user_123/avatar.png', file);
55
56// Edge Functions (Deno)
57// supabase/functions/hello/index.ts
58Deno.serve(async (req) => {
59 return new Response(JSON.stringify({ message: 'Hello!' }));
60});
61```
62
63## Retool
64
65```javascript
66// Retool query (SQL)
67SELECT * FROM orders
68WHERE status = {{ statusDropdown.value }}
69AND created_at >= {{ dateRange.start }}
70ORDER BY created_at DESC
71LIMIT {{ pagination.pageSize }}
72OFFSET {{ (pagination.page - 1) * pagination.pageSize }}
73
74// Retool transformer
75const enriched = data.map(row => ({
76 ...row,
77 total_formatted: `$${row.total.toFixed(2)}`,
78 status_color: row.status === 'paid' ? 'green' : 'red',
79}));
80return enriched;
81```
82
83## n8n Workflow Automation
84
85```json
86{
87 "nodes": [
88 { "type": "n8n-nodes-base.webhook", "name": "Webhook Trigger" },
89 { "type": "n8n-nodes-base.httpRequest", "name": "Fetch Data" },
90 { "type": "n8n-nodes-base.if", "name": "Check Condition" },
91 { "type": "n8n-nodes-base.slack", "name": "Send Notification" }
92 ]
93}
94```
95
96## Integration Patterns
97- **Custom code escape hatches:** When low-code hits limits, embed custom JS/Python
98- **API-first backend:** Use Supabase/Firebase as backend, custom frontend
99- **Hybrid architecture:** Low-code for admin panels, custom code for customer-facing
100- **Data sync:** Webhook-triggered n8n/Zapier workflows between SaaS tools
101- **Self-hosting:** Prefer Appsmith/Tooljet/n8n for data sovereignty requirements