Skip to content

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

  1. Go to Functions in the web console
  2. Click Create → select Write code
  3. Choose a runtime (Node.js or Python)
  4. Write your handler code
  5. Optionally select an event source (PostgreSQL, MySQL, Redis, MinIO)
  6. 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

javascript
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

python
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 functionsImage-based functions
Setup timeSecondsMinutes (build + push image)
DependenciesBuilt-in only (Express/Flask)Any, install in your Dockerfile
Custom packagesNot yet (planned)Full control via package.json / requirements.txt
Best forPrototypes, webhooks, simple handlers, learningProduction 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

bash
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 demand

This 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

FlagDefaultDescription
--imageRequiredContainer image for the function
--triggerhttpTrigger type
--port8080Port the function listens on
--idle-timeout300Seconds of inactivity before scaling to zero
--projectProject name
--environmentTarget environment

How scale-to-zero works

The KEDA HTTP interceptor proxy sits between Traefik and your function. When the function is at zero replicas:

  1. The request arrives at the interceptor
  2. The interceptor holds the connection (the browser waits)
  3. KEDA scales the function from 0 to 1
  4. Once the pod is ready, the interceptor forwards the request
  5. 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

bash
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        running

Status 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

bash
kip function logs webhook-handler --project yourr-name --environment test

Use 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

bash
kip function delete webhook-handler --project yourr-name --environment test

Removes 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 rateReplicas
No traffic (5 min)0
Low traffic1
Moderate traffic2-5
High trafficUp to 10

Functions vs apps vs jobs

AppsFunctionsJobs
Always runningYesNo (scale-to-zero)No (run once/scheduled)
Triggered byHTTP trafficEvents (HTTP, etc.)Schedule or manual
ScalingManual or HPA autoscaleAutomatic (KEDA)N/A
Cold startNone~2-3 secondsN/A
Cost when idleFull pod costZeroZero
Use caseWeb servers, APIs, frontendsWebhooks, event handlers, lightweight APIsBatch 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:

bash
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 test

The 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.

bash
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 8080

Your function receives each row as a JSON POST /event:

json
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.

FlagDescription
--sourceService name created with kip service add postgres
--querySQL query that returns rows to process
--mark-doneSQL to run after each row is processed (optional)

MySQL

Works exactly like PostgreSQL, same flags, same pattern:

bash
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 8080

Redis

Trigger a function when messages appear in a Redis list. The function processes items from the queue.

bash
kip function create send-emails \
  --image registry.example.com/email-sender:latest \
  --trigger redis \
  --source cache \
  --list email-queue \
  --port 8080

KEDA 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.

FlagDescription
--sourceService name created with kip service add redis
--listRedis list name to watch

MinIO

Trigger a function when files are uploaded, modified, or deleted in an S3-compatible bucket.

bash
kip function create process-uploads \
  --image registry.example.com/image-processor:latest \
  --trigger minio \
  --source media \
  --bucket uploads \
  --port 8080

MinIO sends bucket notifications as webhooks to the skipper-poll sidecar, which forwards them to your function as POST /event.

FlagDescription
--sourceService name created with kip service add minio
--bucketBucket 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:

  1. KEDA watches the data source (query result count, list length, bucket events)
  2. When events appear, KEDA scales the function from 0 to 1
  3. skipper-poll connects to the data source and polls for work
  4. Each event is forwarded as POST /event to your function on localhost
  5. Your function processes the event and returns 200
  6. When no events remain, KEDA scales back to 0

Your function code is simple. Just handle POST /event:

javascript
// Node.js example
app.post('/event', (req, res) => {
  console.log('Processing:', req.body)
  // Your logic here
  res.json({ ok: true })
})
python
# Python/Flask example
@app.post('/event')
def handle_event():
    event = request.json
    process(event)
    return {'ok': True}
java
// 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

TriggerSourceScale signalUse case
httpHTTP requestsRequest rateWebhooks, APIs, lightweight endpoints
postgresPostgreSQL queryRow count > 0Process new orders, sync data
mysqlMySQL queryRow count > 0Same as PostgreSQL
redisRedis listList length > 0Job queues, message processing
minioS3 bucket eventsFile uploaded/deletedImage processing, file conversion

Released under the Apache 2.0 License.