What Is a Cold Start?
A cold start occurs when a serverless function is invoked and no existing runtime container is available to handle it. The platform must create a new container, load your runtime (Node.js, Python, etc.), initialize your code, and then execute the function. This initialization phase adds latency — anywhere from a few hundred milliseconds to several seconds depending on the platform and runtime.
Contrast this with a warm start: the container from a previous invocation is still alive, and the platform routes the new request directly to it. Warm starts are fast — often under 10ms of platform overhead.
Why Cold Starts Happen
Cold starts occur when:
- 1The function has never been invoked — fresh deployment with no prior invocations
- 2Traffic spikes — demand exceeds the number of warm containers, so new ones must be created
- 3A container has been idle too long — platforms recycle containers after a period of inactivity
- 4A new version was deployed — existing warm containers run the old version; new containers must be created for the updated code
Measuring Cold Start Impact
The cold start penalty varies by:
- Runtime — Node.js and Python are generally faster to initialize than Java or .NET
- Bundle size — Larger packages mean longer loading time
- Dependencies — Heavy initialization (database connections, config loading) adds to startup time
For user-facing API endpoints where p99 latency matters, a 500ms cold start on an otherwise 50ms function is a 10× latency spike. For background processing or webhooks, the same cold start is usually imperceptible.
Writing Cold-Start-Friendly Functions
Keep your function small
The most effective way to reduce cold start time is to reduce what needs to be loaded. Only import what you need:
// ❌ Avoid: importing entire libraries when you need one function
const _ = require('lodash');
const result = _.get(obj, 'a.b.c');
// ✅ Better: targeted import or native alternative
const result = obj?.a?.b?.c;Move initialization outside the handler
Code outside the main function runs once when the container starts and is reused on warm invocations. Use this for expensive setup:
// config.js — database client initialized once per container
const { Pool } = require('pg');
// Runs once on cold start, reused on warm starts
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const main = async (params) => {
const { userId } = params;
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);
return {
statusCode: 200,
body: JSON.stringify({ user: result.rows[0] })
};
};
module.exports = { main };The same pattern applies in Python:
# handler.py
import json
import psycopg2
import os
# Initialized once per container lifetime
conn = psycopg2.connect(os.environ['DATABASE_URL'])
def main(params):
user_id = params.get('userId')
if not user_id:
return {'statusCode': 400, 'body': json.dumps({'error': 'userId required'})}
cursor = conn.cursor()
cursor.execute('SELECT id, email FROM users WHERE id = %s', (user_id,))
row = cursor.fetchone()
if not row:
return {'statusCode': 404, 'body': json.dumps({'error': 'Not found'})}
return {'statusCode': 200, 'body': json.dumps({'id': row[0], 'email': row[1]})}Minimize cold initialization work
Defer work that is not needed on every invocation:
let configCache = null;
const getConfig = async () => {
if (configCache) return configCache; // warm: instant
configCache = await fetchRemoteConfig(); // cold: one-time fetch
return configCache;
};
const main = async (params) => {
const config = await getConfig();
// use config...
};
module.exports = { main };Keeping Functions Warm
The most direct way to eliminate cold starts for critical functions is to keep the container alive with periodic invocations.
PandaStack's cronjob system is perfect for this. Set up a cronjob to invoke your function every 5 minutes:
panda cronjobs create --name keep-warm-hello-fn --schedule "*/5 * * * *" --image curlimages/curl --command "curl -s https://functions.pandastack.io/api/v1/namespaces/_/actions/hello-fn"This keeps the container warm without requiring any changes to your function code.
Architectural Strategies
- Decouple cold-start-sensitive paths — use warm containers for user-facing endpoints; accept cold starts in background jobs
- Batch invocations — fewer, larger requests mean fewer container creations per unit of work
- Use cronjobs as warmers — PandaStack cronjobs can ping any HTTP endpoint on any schedule
Conclusion
Cold starts are real, but they are manageable. Write lean functions, initialize resources outside your handler, and use PandaStack cronjobs to keep critical functions warm. For most workloads, these strategies bring cold start impact well within acceptable thresholds. Manage your functions and cronjobs at dashboard.pandastack.io.