CI/CD for Tenklo Functions
How to integrate Tenklo Function deployments into your CI/CD pipeline.
CI/CD for Tenklo is about keeping your Functions — sync functions, action functions, webhook functions, and event functions — in sync with your application across environments.
The core principle: deploy to Tenklo as part of the same pipeline step as your application. Deploying them separately risks your app and your Functions going out of sync, which can cause subtle bugs that are hard to trace.
Authentication
To deploy from CI, you need a scoped API key for each Tenklo environment.
- Create API keys: In the Tenklo UI, go to Environment Settings > API Keys and create a key for each environment (e.g.,
devandprod). For CI/CD pipelines, use a key scoped toenvironment:deployonly — see the CI/CD Deploy profile. - Store the keys: Add them as secrets in your CI/CD provider. The Tenklo CLI reads them from these environment variables:
NANGO_SECRET_KEY_DEVNANGO_SECRET_KEY_PROD
Recommended pipeline
Treat Tenklo Functions like application code: validate on every PR, deploy to each environment in the same step as your application.
| Pipeline stage | What to do |
|---|---|
| Pull request | Run nango compile and npm test as required checks. Block merge on failure. |
| Merge to main | Deploy to your dev/staging Tenklo environment alongside your app. |
| Release to production | Deploy to your prod Tenklo environment in the same step as your app release. |
The Tenklo CLI deploy command targets a specific environment:
nango deploy <environment>If you don't specify an environment, it defaults to dev.
If you don't have a staging environment, wire the prod Tenklo deploy directly to your production release step — use a workflow_dispatch trigger or equivalent manual approval. This keeps production deploys intentional, and ensures they always happen through CI using the prod API key rather than from a local machine.
Add the dist/ folder inside your nango-integrations directory to .gitignore. The CLI writes compiled JS artifacts there, and committing them creates noisy diffs and risks deploying stale bundles.
Example: GitHub Actions
Two workflow files implement the pipeline above.
PR validation (.github/workflows/nango-validate.yml)
name: Validate Nango Functions
on:
pull_request:
branches:
- main
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Compile
run: npx nango@latest compile --no-dependency-update
- name: Test
run: npm testDeploy (.github/workflows/nango-deploy.yml)
name: Deploy Nango Functions
on:
# Manual trigger to deploy to a specific environment
workflow_dispatch:
inputs:
stage:
type: choice
description: 'Environment to deploy to'
required: true
default: 'dev'
options:
- dev
- prod
allowDestructive:
type: boolean
description: 'Allow destructive changes'
required: true
default: false
# Automatic deploy to dev on merge to main
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
env:
NANGO_SECRET_KEY_DEV: ${{ secrets.NANGO_SECRET_KEY_DEV }}
NANGO_SECRET_KEY_PROD: ${{ secrets.NANGO_SECRET_KEY_PROD }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Deploy to Nango
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
stage="${{ inputs.stage }}"
else
stage="dev"
fi
secret_key_var="NANGO_SECRET_KEY_$(echo "$stage" | tr '[:lower:]' '[:upper:]')"
secret_key="${!secret_key_var}"
if [ -z "$secret_key" ]; then
echo "Error: ${secret_key_var} is not set"
exit 1
fi
destructive_flag=""
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ "${{ inputs.allowDestructive }}" == "true" ]; then
destructive_flag="--allow-destructive"
fi
npx nango@latest deploy "$stage" --secret-key "$secret_key" --no-dependency-update $destructive_flagDestructive Changes
A destructive change removes an integration, sync function, or action function. To prevent accidental deletions, nango deploy will prompt for confirmation when it detects one.
In CI, use --auto-confirm or --allow-destructive to bypass the prompt. We recommend only doing this on a manual trigger, as shown above.
Testing in CI
Run your test suite in CI before every deployment. Tenklo's testing framework uses dry runs and snapshot testing to validate your Functions without affecting live data:
npm testSee the Testing integrations guide for details.
Ephemeral preview environments (e.g. Vercel)
If you use ephemeral preview environments — such as Vercel preview deployments — as your staging layer, you'll run into a challenge: each preview has a unique URL, but Tenklo webhook URLs must be registered in advance and point to a stable destination.
Tenklo doesn't currently support creating environments programmatically. This is on the roadmap and will make ephemeral environment setups much cleaner when available.
For now, the simplest approach is to designate a fixed, long-lived Tenklo environment (e.g., dev) specifically for Nango-related changes, and use that consistently across preview deployments rather than trying to create a new Nango environment per preview.
If you need previews to receive live webhook events, a proxy server is the current workaround: register a stable URL in Tenklo, and have the proxy forward incoming webhooks to the correct preview URL.
Dependency-safe CI and monorepos
When running Tenklo in CI or monorepos, you often want to avoid modifying package.json or running extra installs from within Tenklo commands. Use --no-dependency-update on CLI commands, or set NANGO_CLI_DEPENDENCY_UPDATE=false as an environment variable:
npx nango@latest deploy dev --no-dependency-updateWith --no-dependency-update, Tenklo will not install dependencies. Make sure your pipeline does so first (e.g. npm ci, pnpm install --frozen-lockfile, yarn install --immutable, or bun install --frozen-lockfile).
In CI environments, Tenklo automatically disables dependency updates to prevent modifying package.json. Passing --no-dependency-update explicitly silences the related warning.
Related resources
- Testing integrations - A comprehensive guide to testing your Tenklo Functions.
- API Keys reference - Available scopes and advised profiles for CI/CD and other use cases.