Use this skill when writing app code with InsForge or @insforge/sdk: database CRUD, auth, storage uploads/storage RLS, functions, AI, realtime, emails, Stripe checkout, subscriptions, customer portal flows, or pointing S3-compatible tooling (aws CLI, AWS SDKs, rclone, Terraform, boto3) at InsForge Storage. Trigger on requests like add auth, fetch data, upload files, make a bucket public, add checkout, sell subscriptions, or send email. For infrastructure, SQL migrations, CLI commands, or Stri...
Scanned 9/8/2026
Install to Claude Code
npx -y skills add agisota/old-one --skill insforge --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Insforge?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/agisota-insforge)More formats (shields.io, HTML) on the badges page.
---
name: insforge
description: >-
Use this skill when writing app code with InsForge or @insforge/sdk: database CRUD, auth, storage uploads/storage RLS, functions, AI, realtime, emails, Stripe checkout, subscriptions, customer portal flows, or pointing S3-compatible tooling (aws CLI, AWS SDKs, rclone, Terraform, boto3) at InsForge Storage. Trigger on requests like add auth, fetch data, upload files, make a bucket public, add checkout, sell subscriptions, or send email. For infrastructure, SQL migrations, CLI commands, or Stripe key/catalog setup, use insforge-cli instead.
license: MIT
metadata:
author: insforge
version: "1.3.0"
organization: InsForge
date: April 2026
---
# InsForge SDK Skill
This skill covers **client-side SDK integration** using `@insforge/sdk`. For backend infrastructure operations (creating tables, inspecting schema, deploying functions, secrets, managing storage buckets, configuring Stripe keys/catalog, website deployments, cron job and schedules, logs, etc.), use the **insforge-cli** skill.
## Quick Setup
### 1. Install the SDK
```bash
npm install @insforge/sdk@latest
```
### 2. Set up environment variables
Before using the SDK, create a `.env` file (or `.env.local` for Next.js) in your project root with your InsForge URL and anon key.
#### How to get your URL and anon key
1. **Ensure the project is linked.** Check for `.insforge/project.json` in the project root.
- If it doesn't exist, run `npx @insforge/cli link` (existing project) or `npx @insforge/cli create` (new project) to generate it.
2. **Get the anon key** via the CLI:
```bash
npx @insforge/cli secrets get ANON_KEY
```
3. **Get the URL** from the `oss_host` field in `.insforge/project.json` (e.g., `https://myapp.us-east.insforge.app`).
4. **Write both values** to the `.env` file using the correct framework prefix (see table below).
> **Important:** Use the anon key for SDK clients, including SSR. Use the API key only for privileged backend operations that need admin/service access; it is a full-access admin key, equivalent to a service role key on other platforms.
Use the correct environment variable prefix and access pattern for your framework:
| Framework | `.env` file | Variables | Access Pattern |
|-----------|-------------|-----------|----------------|
| **Next.js** | `.env.local` | `NEXT_PUBLIC_INSFORGE_URL`, `NEXT_PUBLIC_INSFORGE_ANON_KEY` | `process.env.NEXT_PUBLIC_*` |
| **Vite** (React, Vue, Svelte) | `.env` | `VITE_INSFORGE_URL`, `VITE_INSFORGE_ANON_KEY` | `import.meta.env.VITE_*` |
| **Astro** | `.env` | `PUBLIC_INSFORGE_URL`, `PUBLIC_INSFORGE_ANON_KEY` | `import.meta.env.PUBLIC_*` |
| **SvelteKit** | `.env` | `PUBLIC_INSFORGE_URL`, `PUBLIC_INSFORGE_ANON_KEY` | `import { env } from '$env/dynamic/public'` |
| **Create React App** | `.env` | `REACT_APP_INSFORGE_URL`, `REACT_APP_INSFORGE_ANON_KEY` | `process.env.REACT_APP_*` |
| **Node.js / Server** | `.env` | `INSFORGE_URL`, `INSFORGE_ANON_KEY` | `process.env.*` |
Example `.env.local` for Next.js:
```bash
NEXT_PUBLIC_INSFORGE_URL=https://your-appkey.us-east.insforge.app
NEXT_PUBLIC_INSFORGE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
```
> **Important:** Never commit `.env` files to version control. Add `.env`, `.env.local`, and `.env*.local` to your `.gitignore` (keep `.env.example` for documenting required variables).
### 3. Initialize the client
```javascript
import { createClient } from '@insforge/sdk'
// Next.js / CRA: use process.env
const insforge = createClient({
baseUrl: process.env.NEXT_PUBLIC_INSFORGE_URL,
anonKey: process.env.NEXT_PUBLIC_INSFORGE_ANON_KEY
})
// Vite / Astro: use import.meta.env
const insforge = createClient({
baseUrl: import.meta.env.VITE_INSFORGE_URL,
anonKey: import.meta.env.VITE_INSFORGE_ANON_KEY
})
```
## Module Reference
| Module | SDK Integration |
|--------|-----------------|
| **Database** | [database/sdk-integration.md](database/sdk-integration.md) |
| **Auth** | [auth/sdk-integration.md](auth/sdk-integration.md) |
| **Storage** | [storage/sdk-integration.md](storage/sdk-integration.md) |
| **Functions** | [functions/sdk-integration.md](functions/sdk-integration.md) |
| **AI** | [ai/sdk-integration.md](ai/sdk-integration.md) |
| **Real-time** | [realtime/sdk-integration.md](realtime/sdk-integration.md) |
| **Email** | [email/sdk-integration.md](email/sdk-integration.md) |
| **Payments** | [payments/sdk-integration.md](payments/sdk-integration.md) |
### What Each Module Covers
| Module | Content |
|--------|---------|
| **Database** | CRUD operations, filters, pagination, RPC calls |
| **Auth** | Sign up/in, OAuth, sessions, profiles, password reset |
| **Storage** | Upload, download, delete files; S3-compatible gateway for CI / backup tooling; write RLS policies for buckets |
| **Functions** | Invoke edge functions |
| **AI** | Chat completions, image generation, embeddings |
| **Email** | Send custom transactional HTML emails (welcome, newsletter, notifications) |
| **Payments** | Stripe Checkout Sessions, subscriptions, and Billing Portal redirects |
| **Real-time** | Connect, subscribe, publish events, and track presence snapshots plus join/leave deltas |
### Guides
| Guide | When to Use |
|-------|-------------|
| [database/postgres-rls.md](database/postgres-rls.md) | Writing or reviewing RLS policies — covers infinite recursion prevention, `SECURITY DEFINER` patterns, performance tips, and common InsForge RLS patterns |
| [storage/s3-gateway.md](storage/s3-gateway.md) | Fallback path when the consumer is existing S3 tooling (aws CLI, AWS SDKs, rclone, Terraform, boto3) and adopting `@insforge/sdk` is impractical — covers endpoint/region setup, access-key management, path-style addressing, and supported vs. not-supported S3 operations. **Requires InsForge 2.0.9+.** **Prefer the SDK** ([storage/sdk-integration.md](storage/sdk-integration.md)) for app code |
| [storage/postgres-rls.md](storage/postgres-rls.md) | Writing RLS policies for `storage.objects` — owner-only, public-read, path-scoped, team-shared, and the `NULL uploaded_by` caveat for mixed REST + S3 buckets |
| [database/pgvector.md](database/pgvector.md) | Building semantic search, recommendations, or RAG — covers the `vector` extension, schema/dimensions, distance operators, HNSW/IVFFlat indexes, and RPC similarity search |
| [ai/embeddings-and-rag.md](ai/embeddings-and-rag.md) | Generating embeddings through the InsForge AI gateway, storing them in pgvector, and wiring up a basic RAG pipeline with chat completions |
| [payments/backend-configuration.md](payments/backend-configuration.md) | Configuring Stripe keys, syncing catalog, creating products/prices, webhooks, and portal RLS before app integration |
### Building Checkout for a New App
Before integrating payments, make sure a Stripe key is configured. Run `npx @insforge/cli payments status`. If it shows `unconfigured`, ask the user for the Stripe key first. See [payments/backend-configuration.md](payments/backend-configuration.md).
### Real-time Configuration
For real-time channels and database triggers, use SQL migrations or database admin tooling to configure channels, triggers, and policies. The real-time SDK is for frontend event handling and messaging, not backend configuration.
#### Create Database Triggers
Automatically publish events when database records change.
```sql
-- Create trigger function
CREATE OR REPLACE FUNCTION notify_order_changes()
RETURNS TRIGGER AS $$
BEGIN
PERFORM realtime.publish(
'order:' || NEW.id::text, -- channel
TG_OP || '_order', -- event: INSERT_order, UPDATE_order
jsonb_build_object(
'id', NEW.id,
'status', NEW.status,
'total', NEW.total
)
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Attach to table
CREATE TRIGGER order_realtime
AFTER INSERT OR UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION notify_order_changes();
```
#### Conditional Trigger (Status Changes Only)
```sql
CREATE OR REPLACE FUNCTION notify_order_status()
RETURNS TRIGGER AS $$
BEGIN
PERFORM realtime.publish(
'order:' || NEW.id::text,
'status_changed',
jsonb_build_object('id', NEW.id, 'status', NEW.status)
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER order_status_trigger
AFTER UPDATE ON orders
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION notify_order_status();
```
#### Access Control (RLS)
RLS is disabled by default. To restrict channel access:
- **Enable RLS**
```sql
ALTER TABLE realtime.channels ENABLE ROW LEVEL SECURITY;
ALTER TABLE realtime.messages ENABLE ROW LEVEL SECURITY;
```
- **Restrict Subscribe (SELECT on channels)**
```sql
CREATE POLICY "users_subscribe_own_orders"
ON realtime.channels FOR SELECT
TO authenticated
USING (
pattern = 'order:%'
AND EXISTS (
SELECT 1 FROM orders
WHERE id = NULLIF(split_part(realtime.channel_name(), ':', 2), '')::uuid
AND user_id = auth.uid()
)
);
```
- **Restrict Publish (INSERT on messages)**
```sql
CREATE POLICY "members_publish_chat"
ON realtime.messages FOR INSERT
TO authenticated
WITH CHECK (
channel_name LIKE 'chat:%'
AND EXISTS (
SELECT 1 FROM chat_members
WHERE room_id = NULLIF(split_part(channel_name, ':', 2), '')::uuid
AND user_id = auth.uid()
)
);
```
- **Quick Reference**
| Task | SQL |
|------|-----|
| Create channel | `INSERT INTO realtime.channels (pattern, description, enabled) VALUES (...)` |
| Create trigger | `CREATE TRIGGER ... EXECUTE FUNCTION ...` |
| Publish from SQL | `PERFORM realtime.publish(channel, event, payload)` |
| Enable RLS | `ALTER TABLE realtime.channels ENABLE ROW LEVEL SECURITY` |
#### Best Practices
1. **Create channel patterns first** before subscribing from frontend
- Insert channel patterns into `realtime.channels` table
- Ensure `enabled` is set to `true`
2. **Use specific channel patterns**
- Use wildcard `%` patterns for dynamic channels (e.g., `order:%` for `order:123`)
- Use exact patterns for global channels (e.g., `notifications`)
#### Common Mistakes
| Mistake | Solution |
|---------|----------|
| Subscribing to undefined channel pattern | Create channel pattern in `realtime.channels` first |
| Channel not receiving messages | Ensure channel `enabled` is `true` |
| Publishing without trigger | Create database trigger to auto-publish on changes |
#### Recommended Workflow
```text
1. Create channel patterns → INSERT INTO realtime.channels
2. Ensure enabled = true → Set enabled to true
3. Create triggers if needed → Auto-publish on database changes
4. Proceed with SDK subscribe → Use channel name matching pattern
```
### Backend Configuration (Not Yet in CLI)
These modules still require HTTP API calls because the CLI does not yet support them:
| Module | Backend Configuration |
|--------|----------------------|
| **AI** | [ai/backend-configuration.md](ai/backend-configuration.md) |
> Auth redirect URL allowlist is now managed via the CLI — use `npx @insforge/cli config export/plan/apply`. Other auth settings (password policy, OAuth providers, verification methods) still live on the dashboard. See the **insforge-cli** skill's Configuration section.
### Risky backend changes? Use a branch first
When a code change in this skill depends on a **schema migration**, **new RLS policy**, **OAuth provider config change**, or any other backend change that could brick prod, create a backend branch first instead of editing the live project. Branches share `JWT_SECRET` (existing user JWTs keep working) but get a fresh database + EC2 + `API_KEY` / `ANON_KEY`, so you can test the SDK + backend change end-to-end in isolation.
The full branching workflow lives in the **insforge-cli** skill — see [branch](../insforge-cli/references/branch.md) for the decision guide and lifecycle commands. Typical loop:
```bash
npx @insforge/cli branch create feat-x --mode schema-only
# ... apply migrations / change auth config / update RLS on the branch ...
# ... test the SDK against the branch backend ...
npx @insforge/cli branch merge feat-x --dry-run # review SQL
npx @insforge/cli branch merge feat-x # apply to parent
```
> ⚠ **After `branch create` or `branch switch`**, the SDK's `INSFORGE_URL` and `INSFORGE_ANON_KEY` change. **Restart your dev server** (or re-source `.env`) so the SDK starts talking to the branch backend. If you don't, the SDK will silently keep hitting parent — the #1 cause of "I switched but my changes aren't showing up".
## SDK Quick Reference
All SDK methods return `{ data, error }`.
| Module | Methods |
|--------|---------|
| `insforge.database` | `.from().select()`, `.insert()`, `.update()`, `.delete()`, `.rpc()` |
| `insforge.auth` | `.signUp()`, `.signInWithPassword()`, `.signInWithOAuth()`, `.signOut()`, `.getCurrentUser()` |
| `insforge.storage` | `.from().upload()`, `.uploadAuto()`, `.download()`, `.remove()` |
| `insforge.functions` | `.invoke()` |
| `insforge.ai` | `.chat.completions.create()`, `.images.generate()`, `.embeddings.create()` |
| `insforge.realtime` | `.connect()`, `.subscribe()`, `.publish()`, `.on()`, `.disconnect()` |
| `insforge.emails` | `.send({ to, subject, html, cc?, bcc?, from?, replyTo? })` |
| `insforge.payments` | `.createCheckoutSession()`, `.createCustomerPortalSession()` |
## Important Notes
- **Database inserts require array format**: `insert([{...}])` not `insert({...})`
- **Next.js / SSR auth**: Use `createClient({ isServerMode: true })`, keep tokens in httpOnly cookies, and perform auth flows on the server. See [auth/sdk-integration.md](auth/sdk-integration.md)
- **Storage**: Save both `url` AND `key` to database for download/delete operations
- **Functions invoke URL**: `/functions/{slug}` (without `/api` prefix)
- **Payments**: Configure Stripe keys/catalog with `npx @insforge/cli payments ...` first; frontend code only creates Checkout/Portal sessions.
- **Payment RLS**: Before subscription checkout or Billing Portal UI, add app-specific RLS on `payments.checkout_sessions` and `payments.customer_portal_sessions`.
- **Use Tailwind CSS v3.4** (do not upgrade to v4)
- **Always local build before deploy**: Prevents wasted build resources and faster debugging
- **Deprecated packages**: `@insforge/react`, `@insforge/nextjs`, and `@insforge/react-router` are **deprecated**. Do NOT install or use them. Use `@insforge/sdk` directly for all features including authentication.
- **Deployment**: Include a `vercel.json` in the project root for SPA routing (React, React Router apps). The `download-template` tool includes this automatically.
- **Branching for risky backend changes**: If your SDK code depends on a new schema, RLS policy, or auth config change, create a branch via `npx @insforge/cli branch create` first — see the **insforge-cli** skill's [branch](../insforge-cli/references/branch.md) reference. After `branch create` / `branch switch`, **restart the dev server** so the SDK picks up the new `INSFORGE_URL` / `INSFORGE_ANON_KEY`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!