Functions
Skipper functions are serverless workloads that scale to zero when idle and wake up automatically on demand. No traffic means no pods running and no resources consumed. When a request arrives, the function starts in seconds, handles the request, and scales back down after an idle period.
Under the hood, functions use the KEDA HTTP Add-on, an interceptor proxy that queues incoming requests while the function pod starts. No requests are lost, even during cold starts.
Inline functions (write code in the console)
The fastest way to create a function. Write code directly in the web console. No Docker image, no build pipeline, no registry. Just write your handler, click deploy, and it's live with a public URL in seconds.
Skipper provides two runtime base images:
- Node.js 20: Express-based, handles HTTP and event triggers
- Python 3.12: Flask-based, same capabilities
Creating an inline function
- Go to Functions in the web console
- Click Create → select Write code
- Choose a runtime (Node.js or Python)
- Write your handler code
- Optionally select an event source (PostgreSQL, MySQL, Redis, MinIO)
- Click Deploy function
Your code is stored in a Kubernetes ConfigMap and mounted into the runtime container. The function scales to zero when idle, just like image-based functions.
Node.js handler
module.exports = async (event, context) => {
// HTTP trigger: event is the request body, context has method/headers/path
// Event trigger: event is the row/item from the data source
console.log('Processing:', event)
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: { processed: true, timestamp: new Date().toISOString() }
}
}Python handler
def handler(event, context=None):
# event is the request body (HTTP) or row/item (event trigger)
print('Processing:', event)
return {'processed': True}Editing code
Click the code icon on any inline function to open the editor panel. Edit your code and click Save & deploy. The function restarts with the new code in seconds. The editor supports:
- Syntax highlighting (JavaScript / Python)
- Resizable panel (drag the left edge)
- Fullscreen mode (expand icon in the header)
AI code assistant
The editor includes a built-in AI assistant. Click the magic wand icon in the editor toolbar to open the chat panel. The chat opens side-by-side with the code editor, so you can see your code while asking questions.
The assistant understands the function's runtime, trigger type, and connected services. Ask it to generate a handler, explain an error, or refactor existing code. When it suggests changes, click Apply to editor to insert the generated code directly into the editor. Review the diff before saving.
The AI assistant requires an AI provider to be configured in the Settings page. See Configuration: AI provider for setup.
When to use inline vs image-based functions
| Inline functions | Image-based functions | |
|---|---|---|
| Setup time | Seconds | Minutes (build + push image) |
| Dependencies | Built-in only (Express/Flask) | Any, install in your Dockerfile |
| Custom packages | Not yet (planned) | Full control via package.json / requirements.txt |
| Best for | Prototypes, webhooks, simple handlers, learning | Production workloads with dependencies |
Image-based functions
For functions that need custom dependencies, a specific runtime version, or complex logic, use a Docker image.
Creating a function
kip function create webhook-handler \
--image registry.example.com/webhook-handler:latest \
--trigger http \
--port 8080 \
--project yourr-name --environment test Creating function webhook-handler...
Trigger: http
Image: registry.example.com/webhook-handler:latest
Idle timeout: 300s
URL: https://fn-webhook-handler-46-225-91-12.kipper.run
✔ Function webhook-handler created, will scale from 0 on demandThis creates a Function Custom Resource (getkipper.com/v1alpha1). The reconciler manages the underlying resources:
- A Deployment starting at 0 replicas (no resources consumed)
- A Service exposing the function's port
- A KEDA HTTPScaledObject that manages scaling based on request rate
- An Ingress with automatic TLS, giving your function a public URL immediately
Flags
| Flag | Default | Description |
|---|---|---|
--image | Required | Container image for the function |
--trigger | http | Trigger type |
--port | 8080 | Port the function listens on |
--idle-timeout | 300 | Seconds of inactivity before scaling to zero |
--project | — | Project name |
--environment | — | Target environment |
How scale-to-zero works
The KEDA HTTP interceptor proxy sits between Traefik and your function. When the function is at zero replicas:
- The request arrives at the interceptor
- The interceptor holds the connection (the browser waits)
- KEDA scales the function from 0 to 1
- Once the pod is ready, the interceptor forwards the request
- The response is returned. No errors, no lost requests
Cold start time is typically 2-3 seconds depending on the image size. Subsequent requests while the function is warm are instant.
After the idle timeout (default 5 minutes), KEDA scales the function back to zero.
URL format
Every HTTP function gets a public URL automatically:
https://fn-<name>-<cluster-domain>For example: https://fn-webhook-handler-46-225-91-12.kipper.run
URLs are unique within a cluster. Skipper prevents duplicate hostnames across all apps and functions.
Managing functions
List functions
kip function list --project yourr-name --environment test NAME TRIGGER IMAGE STATUS
webhook-handler http registry.example.com/webhook:latest idle
email-sender http registry.example.com/email:latest runningStatus values:
- idle: scaled to zero, no pods running, no resources consumed
- scaling: KEDA is starting a pod (cold start in progress)
- running: at least one pod is handling requests
Stream logs
kip function logs webhook-handler --project yourr-name --environment testUse Loki for idle functions
When a function is scaled to zero, there are no pods to stream from. Use the Loki log viewer in the console (History mode) to see logs from previous executions.
Delete a function
kip function delete webhook-handler --project yourr-name --environment testRemoves the Deployment, Service, Ingress, and KEDA HTTPScaledObject.
Auto-scaling under load
Functions don't just scale between 0 and 1. They scale up to 10 replicas based on request rate. If your function receives a burst of traffic, KEDA adds more pods automatically. When traffic drops, pods are removed.
| Request rate | Replicas |
|---|---|
| No traffic (5 min) | 0 |
| Low traffic | 1 |
| Moderate traffic | 2-5 |
| High traffic | Up to 10 |
Functions vs apps vs jobs
| Apps | Functions | Jobs | |
|---|---|---|---|
| Always running | Yes | No (scale-to-zero) | No (run once/scheduled) |
| Triggered by | HTTP traffic | Events (HTTP, etc.) | Schedule or manual |
| Scaling | Manual or HPA autoscale | Automatic (KEDA) | N/A |
| Cold start | None | ~2-3 seconds | N/A |
| Cost when idle | Full pod cost | Zero | Zero |
| Use case | Web servers, APIs, frontends | Webhooks, event handlers, lightweight APIs | Batch tasks, cleanup, migrations |
When to use a function instead of an app
- Infrequent traffic: a webhook endpoint that receives events a few times per hour
- Cost-sensitive: you don't want to pay for a pod running 24/7 for something used rarely
- Event processing: handle uploads, send emails, process payments on demand
- Development/staging: endpoints you need available but don't want consuming resources
When to use an app instead of a function
- Constant traffic: a website or API with steady request volume
- Low latency required: cold starts are unacceptable
- WebSocket connections: long-lived connections don't work with scale-to-zero
- Complex startup: Java apps with 30-second startup times
Web console
Functions are managed from the Functions page in the web console (Zap icon in the sidebar):
- Write code: create an inline function with the built-in code editor (Node.js or Python)
- Use image: create a function from a Docker image
- Edit code: click the code icon to open the editor, modify and redeploy in seconds
- Event sources: select a service (PostgreSQL, MySQL, Redis, MinIO) as an event trigger
- View status: see which functions are idle, scaling, or running
- Logs: click a function to view Loki-based log history with search and time range
- URL: clickable link to the function's public URL
- Delete: remove the function and all its resources
The editor panel supports drag-to-resize and fullscreen mode for comfortable code editing. Press ESC or click outside to close any panel.
Resource limits
Configure CPU and memory limits for your functions from the Resources tab in the function detail panel. Click a function in the web console, switch to the Resources tab, and adjust the CPU and memory requests and limits.
Resource limits control how much CPU and memory each function pod is allowed to consume. Setting appropriate limits prevents a single function from starving other workloads on the cluster. The defaults work for most lightweight handlers, but functions that process large payloads or run compute-heavy logic may need higher limits.
Changes take effect on the next scale-up. If the function is currently scaled to zero, the new limits apply when the next request triggers a cold start. If the function is running, it restarts with the updated limits.
Security settings
Functions have the same security settings as apps. Open the function detail panel → Settings tab to configure:
- Security headers: toggle HSTS, CSP, XSS protection on or off
- CSP allowlist: add external domains (comma-separated) to the Content Security Policy
For example, if your function serves an HTML page that loads Google Fonts, add fonts.googleapis.com to the CSP allowlist.
See Security: CSP allowlist for details.
Environment variables and secrets
Functions support the same environment variable and secret management as apps:
kip app env set webhook-handler LOG_LEVEL=debug --project yourr-name --environment test
kip app secret set webhook-handler API_KEY --project yourr-name --environment testThe kip app env and kip app secret commands work with functions because they share the same underlying Kubernetes resources (Deployments, Secrets).
Trigger types
HTTP
The default trigger. Your function gets a public URL and scales based on HTTP request rate. Powered by the KEDA HTTP Add-on with interceptor proxy for zero-downtime cold starts.
PostgreSQL
Trigger a function when new rows appear in a database table. KEDA watches the query result. When the count is above zero, the function scales up and processes the rows.
kip function create process-orders \
--image registry.example.com/order-processor:latest \
--trigger postgres \
--source mydb \
--query "SELECT * FROM orders WHERE status = 'pending'" \
--mark-done "UPDATE orders SET status = 'done' WHERE id = {{id}}" \
--port 8080Your function receives each row as a JSON POST /event:
POST /event
{
"id": 42,
"customer": "acme",
"amount": 99.99,
"status": "pending"
}The --mark-done flag is optional. When set, Skipper automatically runs the query after your function returns 200, preventing the same row from being processed twice. The placeholder is replaced with the value from the row.
| Flag | Description |
|---|---|
--source | Service name created with kip service add postgres |
--query | SQL query that returns rows to process |
--mark-done | SQL to run after each row is processed (optional) |
MySQL
Works exactly like PostgreSQL, same flags, same pattern:
kip function create sync-users \
--image registry.example.com/user-sync:latest \
--trigger mysql \
--source mydb \
--query "SELECT * FROM users WHERE synced = 0" \
--mark-done "UPDATE users SET synced = 1 WHERE id = {{id}}" \
--port 8080Redis
Trigger a function when messages appear in a Redis list. The function processes items from the queue.
kip function create send-emails \
--image registry.example.com/email-sender:latest \
--trigger redis \
--source cache \
--list email-queue \
--port 8080KEDA watches the list length. When items are pushed to email-queue, the function scales up. Each item is forwarded to your function as POST /event.
| Flag | Description |
|---|---|
--source | Service name created with kip service add redis |
--list | Redis list name to watch |
MinIO
Trigger a function when files are uploaded, modified, or deleted in an S3-compatible bucket.
kip function create process-uploads \
--image registry.example.com/image-processor:latest \
--trigger minio \
--source media \
--bucket uploads \
--port 8080MinIO sends bucket notifications as webhooks to the skipper-poll sidecar, which forwards them to your function as POST /event.
| Flag | Description |
|---|---|
--source | Service name created with kip service add minio |
--bucket | Bucket name to watch for events |
How event triggers work
For non-HTTP triggers, Skipper automatically injects a lightweight sidecar container called skipper-poll into the function pod:
- KEDA watches the data source (query result count, list length, bucket events)
- When events appear, KEDA scales the function from 0 to 1
- skipper-poll connects to the data source and polls for work
- Each event is forwarded as
POST /eventto your function onlocalhost - Your function processes the event and returns 200
- When no events remain, KEDA scales back to 0
Your function code is simple. Just handle POST /event:
// Node.js example
app.post('/event', (req, res) => {
console.log('Processing:', req.body)
// Your logic here
res.json({ ok: true })
})# Python/Flask example
@app.post('/event')
def handle_event():
event = request.json
process(event)
return {'ok': True}// Spring Boot example
@PostMapping("/event")
public Map<String, Boolean> handleEvent(@RequestBody Map<String, Object> event) {
process(event);
return Map.of("ok", true);
}The function doesn't need to know about the data source, connection strings, or polling logic. It just receives events as HTTP requests.
All trigger types
| Trigger | Source | Scale signal | Use case |
|---|---|---|---|
http | HTTP requests | Request rate | Webhooks, APIs, lightweight endpoints |
postgres | PostgreSQL query | Row count > 0 | Process new orders, sync data |
mysql | MySQL query | Row count > 0 | Same as PostgreSQL |
redis | Redis list | List length > 0 | Job queues, message processing |
minio | S3 bucket events | File uploaded/deleted | Image processing, file conversion |
