HEX
Server: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/8.4.25
System: Windows NT DESKTOP-4TAV2RJ 10.0 build 19045 (Windows 10) AMD64
User: fred (0)
PHP: 8.4.25
Disabled: NONE
Upload Files
File: C:/Users/fred/.codex/.tmp/plugins/plugins/base44/skills/base44-cli/references/functions-create.md
# Creating Functions

Base44 functions are serverless backend functions that run on Deno. They are defined locally in your project and deployed to the Base44 backend.

## Function Directory

All function definitions must be placed in the `base44/functions/` folder in your project. Each function lives in its own subdirectory with a configuration file and entry point.

Example structure:
```
my-app/
  base44/
    functions/
      process-order/
        function.jsonc
        index.ts
      send-notification/
        function.jsonc
        index.ts
```

## How to Create a Function

1. Create a new directory in `base44/functions/` with your function name (use kebab-case)
2. Create a `function.jsonc` configuration file in the directory
3. Create the entry point file (e.g., `index.ts`)
4. Deploy the function using the CLI

## Function Configuration

Each function requires a `function.jsonc` configuration file:

```jsonc
{
  "name": "my-function",
  "entry": "index.ts",
  // Optionally add automations
  "automations": [
    {
      "name": "Daily run",
      "type": "scheduled",
      "schedule_mode": "recurring",
      "schedule_type": "cron",
      "cron_expression": "0 9 * * *"
    }
  ]
}
```

### Configuration Properties

| Property | Description | Required |
|----------|-------------|----------|
| `name` | Function name (must match `/^[^.]+$/` - no dots allowed) | Yes |
| `entry` | Entry point file path relative to the function directory (min 1 char) | Yes |
| `automations` | Array of triggers (CRON, simple schedule, one-time, entity hooks); deployed with the function | No |

## Automations

Functions can define automations (triggers) so they run on a schedule or when entity data changes. Add an optional `automations` array to `function.jsonc`. Supported types: **scheduled** (one-time, CRON, or simple interval) and **entity hooks** (on entity create/update/delete). Automations are deployed with the function via `npx base44 functions deploy`. For full schemas and examples, see [automations.md](automations.md).

## Entry Point File

Functions run on Deno and must export using `Deno.serve()`. Use `npm:` prefix for npm packages.

```typescript
import { createClientFromRequest } from "npm:@base44/sdk";

Deno.serve(async (req) => {
  // Get authenticated client from request
  const base44 = createClientFromRequest(req);
  
  // Parse input
  const { orderId, action } = await req.json();
  
  // Your logic here
  const order = await base44.entities.Orders.get(orderId);
  
  // Return response
  return Response.json({
    success: true,
    order: order
  });
});
```

### Request Object

The function receives a standard Deno `Request` object:
- `req.json()` - Parse JSON body
- `req.text()` - Get raw text body
- `req.headers` - Access request headers
- `req.method` - HTTP method

### Response Object

Return using `Response.json()` for JSON responses:

```typescript
// Success response
return Response.json({ data: result });

// Error response with status code
return Response.json({ error: "Something went wrong" }, { status: 400 });

// Not found
return Response.json({ error: "Order not found" }, { status: 404 });
```

## Complete Example

### Directory Structure
```
base44/
  functions/
    process-order/
      function.jsonc
      index.ts
```

### function.jsonc
```jsonc
{
  "name": "process-order",
  "entry": "index.ts"
}
```

### index.ts
```typescript
import { createClientFromRequest } from "npm:@base44/sdk";

Deno.serve(async (req) => {
  try {
    const base44 = createClientFromRequest(req);
    const { orderId } = await req.json();
    
    // Validate input
    if (!orderId) {
      return Response.json(
        { error: "Order ID is required" },
        { status: 400 }
      );
    }
    
    // Fetch and process the order
    const order = await base44.entities.Orders.get(orderId);
    if (!order) {
      return Response.json(
        { error: "Order not found" },
        { status: 404 }
      );
    }
    
    return Response.json({
      success: true,
      orderId: order.id,
      processedAt: new Date().toISOString()
    });
    
  } catch (error) {
    return Response.json(
      { error: error.message },
      { status: 500 }
    );
  }
});
```

## Using Service Role Access

For admin-level operations, use `asServiceRole`:

```typescript
import { createClientFromRequest } from "npm:@base44/sdk";

Deno.serve(async (req) => {
  const base44 = createClientFromRequest(req);
  
  // Check user is authenticated
  const user = await base44.auth.me();
  if (!user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }
  
  // Use service role for admin operations
  const allOrders = await base44.asServiceRole.entities.Orders.list();
  
  return Response.json({ orders: allOrders });
});
```

## Using Secrets

Access environment variables configured in the app dashboard:

```typescript
Deno.serve(async (req) => {
  // Access environment variables (configured in app settings)
  const apiKey = Deno.env.get("STRIPE_API_KEY");
  
  const response = await fetch("https://api.stripe.com/v1/charges", {
    headers: {
      "Authorization": `Bearer ${apiKey}`
    }
  });
  
  return Response.json(await response.json());
});
```

## Naming Conventions

- **Directory name**: Use kebab-case (e.g., `process-order`, `send-notification`)
- **Function name**: Match the directory name, must match pattern `/^[^.]+$/` (no dots allowed)
  - Valid: `process-order`, `send_notification`, `myFunction`
  - Invalid: `process.order`, `send.notification.v2`
- **Entry file**: Typically `index.ts` or `index.js`

## Deploying Functions

After creating your function, deploy it to Base44:

```bash
npx base44 functions deploy
```

For more details on deploying, see [functions-deploy.md](functions-deploy.md).

## Notes

- Functions run on Deno runtime, not Node.js
- Use `npm:` prefix for npm packages (e.g., `npm:@base44/sdk`)
- Use `createClientFromRequest(req)` to get a client that inherits the caller's auth context
- Configure secrets via app dashboard for API keys
- Make sure to handle errors gracefully and return appropriate HTTP status codes

## Common Mistakes

| Wrong | Correct | Why |
|-------|---------|-----|
| `functions/myFunction.js` (single file) | `functions/my-function/index.ts` + `function.jsonc` | Functions require subdirectory with config |
| `import { ... } from "@base44/sdk"` | `import { ... } from "npm:@base44/sdk"` | Deno requires `npm:` prefix for npm packages |
| `MyFunction` or `myFunction` directory | `my-function` directory | Use kebab-case for directory names |