← Files InsForgeARCHIVED FILE

skills/insforge-cli/references/functions-deploy.md

5.43 KB · Oct 4, 2026 · 12:28 UTC

↓ Download file

# npx @insforge/cli functions deploy

Deploy (create or update) an edge function.

## Syntax

```bash
npx @insforge/cli functions deploy <slug> [options]
```

## Options

| Option | Description |
|--------|-------------|
| `--file <path>` | **Required.** Path to the function source file. |
| `--name <name>` | Display name |
| `--description <desc>` | Function description |

The CLI does not prescribe a layout: keep your function source wherever you like and point `--file` at it.

## What It Does

1. Checks if the function already exists (GET)
2. If exists: updates (PUT)
3. If new: creates (POST)

## Usage Examples

```bash
# Deploy a function from its source file
npx @insforge/cli functions deploy my-handler --file ./my-handler.ts

# Deploy with a display name and description
npx @insforge/cli functions deploy cleanup-expired --file ./handler.ts --name "Cleanup Expired" --description "Removes expired records"

# Update an existing function
npx @insforge/cli functions deploy payment-webhook --file ./webhooks/payment.ts
```

## Output

Success message with the slug and action taken (created or updated).

## Function Code Structure

Functions run on Deno Subhosting. Use standard ESM imports and `export default` to define your handler.

- Import `createClient` from `npm:@insforge/sdk`
- Export a default async function that receives a `Request` and returns a `Response`
- Use `Deno.env.get()` to access secrets and environment variables
- Always handle CORS preflight (`OPTIONS`) for browser-invoked functions

### Public Function (No Authentication Required)

```typescript
import { createClient } from 'npm:@insforge/sdk';

export default async function(req: Request): Promise<Response> {
  const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization'
  };

  if (req.method === 'OPTIONS') {
    return new Response(null, { status: 204, headers: corsHeaders });
  }

  // Create client with anon token — no authentication needed
  const client = createClient({
    baseUrl: Deno.env.get('INSFORGE_BASE_URL'),
    anonKey: Deno.env.get('ANON_KEY')
  });

  // Access public data
  const { data, error } = await client.database
    .from('public_posts')
    .select('*')
    .limit(10);

  return new Response(JSON.stringify({ data }), {
    status: 200,
    headers: { ...corsHeaders, 'Content-Type': 'application/json' }
  });
}
```

### Authenticated Function (Access User Data)

```typescript
import { createClient } from 'npm:@insforge/sdk';

export default async function(req: Request): Promise<Response> {
  const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization'
  };

  if (req.method === 'OPTIONS') {
    return new Response(null, { status: 204, headers: corsHeaders });
  }

  // Extract token from request headers
  const authHeader = req.headers.get('Authorization');
  const userToken = authHeader ? authHeader.replace('Bearer ', '') : null;

  // Create client with user's token for authenticated access
  const client = createClient({
    baseUrl: Deno.env.get('INSFORGE_BASE_URL'),
    accessToken: userToken
  });

  // Get authenticated user
  const { data: userData } = await client.auth.getCurrentUser();
  if (!userData?.user?.id) {
    return new Response(JSON.stringify({ error: 'Unauthorized' }), {
      status: 401,
      headers: { ...corsHeaders, 'Content-Type': 'application/json' }
    });
  }

  // Access user's private data or create records with user_id
  await client.database.from('user_posts').insert([{
    user_id: userData.user.id,
    content: 'My post'
  }]);

  return new Response(JSON.stringify({ success: true }), {
    status: 200,
    headers: { ...corsHeaders, 'Content-Type': 'application/json' }
  });
}
```

## Function Status

| Status | Description |
|--------|-------------|
| `draft` | Saved but not deployed |
| `active` | Deployed and invokable |
| `error` | Deployment error |

## Best Practices

1. **Always handle CORS** — include preflight `OPTIONS` handler and CORS headers in every response
2. **Store credentials as secrets** — use `npx @insforge/cli secrets add` for API keys, base URLs, etc.
3. **Check available functions first** before invoking from frontend
   - Call `npx @insforge/cli functions list` to see existing functions
   - Verify the target function exists and has `status: "active"`
4. **Always return a `Response`** — the runtime expects a `Response` object

## Common Mistakes

| Mistake | Solution |
|---------|----------|
| Invoking non-existent function | Check functions first with `npx @insforge/cli functions list`, create if needed |
| Invoking draft function | Ensure function `status` is `"active"` |
| Missing CORS headers | Always handle `OPTIONS` preflight and include CORS headers in responses |
| Forgetting to check auth | For authenticated functions, always verify `getCurrentUser()` before proceeding |

## Recommended Workflow

```
1. Write function code            → wherever you keep source (e.g. ./functions/{slug}.ts)
2. Deploy                         → npx @insforge/cli functions deploy {slug} --file <path>
3. Check status                   → npx @insforge/cli functions list
4. Ensure secrets are set         → npx @insforge/cli secrets add INSFORGE_BASE_URL https://...
5. Invoke from frontend           → insforge.functions.invoke('{slug}', { body: {...} })
```

SHA-256: 6bd3f18e2430090beded1ddb22f3d2bd7928b55362367279356885fa5419a541