Uncontrolled serverless deployments can quietly burn through budgets and introduce risk into environments you didn’t intend to touch. If every push to every branch triggers a deployment, you’re essentially treating your cloud infrastructure like a sandbox — even when it isn’t.
One practical guardrail is simple: only deploy serverless applications when a pull request is opened or updated. Jenkins makes this surprisingly flexible if you wire your pipeline correctly.
Why restrict serverless deployments to pull requests?
Before diving into Jenkins specifics, it helps to understand the motivation:
- Cost control: Serverless deployments (especially with preview environments) can multiply quickly.
- Safer testing: PRs represent code that’s under review — not experimental commits.
- Cleaner environments: Avoid polluting staging or preview stacks with every push.
- Better auditability: Every deployment maps to a reviewable change.
In short, you align infrastructure changes with your code review process.
How Jenkins sees pull requests
Here’s where things get interesting. Jenkins doesn’t inherently “understand” pull requests unless you’re using integrations like:
- GitHub Branch Source Plugin
- Bitbucket Branch Source Plugin
- Multibranch Pipelines
When configured correctly, Jenkins exposes environment variables such as:
CHANGE_IDCHANGE_BRANCHCHANGE_TARGET
If CHANGE_ID exists, you’re inside a pull request build. That becomes our key condition.
A minimal Jenkinsfile example
Let’s start with a straightforward pipeline that deploys only when a PR is detected:
pipeline {
agent any
stages {
stage('Install Dependencies') {
steps {
sh 'npm install'
}
}
stage('Run Tests') {
steps {
sh 'npm test'
}
}
stage('Deploy Serverless') {
when {
expression {
return env.CHANGE_ID != null
}
}
steps {
sh 'npx serverless deploy --stage pr-${env.CHANGE_ID}'
}
}
}
}This simple condition ensures deployments only happen for pull request builds. Regular branch pushes will skip the deployment stage entirely.
Adding more control (because you probably need it)
In real-world pipelines, you rarely want just “PR = deploy.” You might want:
- Only deploy PRs targeting
mainordevelop - Skip drafts
- Limit deployments to certain directories
Here’s a more refined condition:
1stage('Deploy Serverless') {
2 when {
3 allOf {
4 expression { env.CHANGE_ID != null }
5 expression { env.CHANGE_TARGET == 'main' }
6 }
7 }
8 steps {
9 sh 'npx serverless deploy --stage pr-${env.CHANGE_ID}'
10 }
11}This ensures deployments only occur for pull requests merging into main, which is often your production-bound branch.
Preview environments per pull request
A common pattern is spinning up isolated environments per PR. This is where serverless shines — you can create lightweight, temporary stacks.
Example:
1npx serverless deploy \
2 --stage pr-${CHANGE_ID} \
3 --region us-east-1This results in environments like:
pr-101pr-102
Each PR gets its own deployment without interfering with others.
Cleaning up after merge
A common mistake developers make is forgetting teardown logic. These environments don’t disappear automatically.
You can add a cleanup job triggered on PR close:
1pipeline {
2 agent any
3
4 stages {
5 stage('Remove PR Environment') {
6 when {
7 expression { env.CHANGE_ID != null }
8 }
9 steps {
10 sh 'npx serverless remove --stage pr-${env.CHANGE_ID}'
11 }
12 }
13 }
14}This keeps your cloud account tidy and avoids unnecessary charges.
Guarding against accidental deployments
Even with conditions, there are edge cases:
- Manual Jenkins builds
- Misconfigured webhooks
- Replayed builds
To tighten things further, you can combine conditions with branch checks:
1when {
2 allOf {
3 expression { env.CHANGE_ID != null }
4 not {
5 branch 'main'
6 }
7 }
8}This ensures your deployment never runs on direct commits to main.
Using Jenkins Multibranch Pipeline correctly
If you’re not using Multibranch Pipelines, you’re making this harder than it needs to be.
With Multibranch:
- PRs are automatically discovered
- Separate pipelines run per branch/PR
- Environment variables are injected cleanly
Without it, you’ll need custom scripting to detect PRs — which is brittle and unnecessary.
Performance and cost implications
Restricting deployments to pull requests has a noticeable impact:
- Fewer deployments = lower Lambda/API Gateway churn
- Reduced build times in Jenkins
- Less noise in monitoring systems
But there’s a tradeoff: you lose early deployment feedback from regular commits. Some teams address this by:
- Running lightweight validations on push
- Reserving full deployments for PRs
A pattern that works well in practice
One effective setup looks like this:
- Push to branch → run lint + tests
- Open PR → deploy preview environment
- Merge to main → deploy production
This gives you a clean separation between validation, review, and release.
Final thought
Limiting serverless deployments to pull requests isn’t just a Jenkins trick — it’s a discipline. Jenkins simply enforces it.
Once you tie deployments to PRs, your pipeline becomes more predictable, your infrastructure cleaner, and your cloud bill a lot less surprising.
And if you’ve ever wondered why your AWS bill spiked overnight, there’s a good chance this exact change would have prevented it.