How and When to Use callonce vs call in Karate DSL
- 20 May, 2026
One of the most useful features in Karate DSL is the ability to reuse logic by invoking external feature files or utility scripts.
For this, Karate provides two very similar functions: call and callonce.
At first glance they seem almost identical, but their execution behavior is very different:
callexecutes every time it is reached.callonceexecutes once and reuses the cached result.
I realized how important this distinction was while working on a test suite where a utility feature declared in the Background was unintentionally triggering the same API request before every scenario because I was using call instead of callonce.
In small suites this may go unnoticed, but in larger suites it can lead to unnecessary API traffic, slower execution times, and redundant setup operations.
That’s why understanding when to use each one is essential for building scalable and efficient Karate test suites.
Where These Functions Can Be Used
Both call and callonce can be used:
- inside a
Background, - or directly inside a
Scenario.
However, their impact becomes more noticeable when used in a Background, because the Background executes before every scenario.
Example
Background:
* def auth = call read('utils/get-auth-token.feature')
If the feature contains 10 scenarios, the authentication feature above will execute 10 times.
In cases like this, callonce is often the better choice.
1. Using call (For Fresh or Independent Data)
Use call when each scenario needs its own unique or isolated data.
This is useful when:
- Tests should not share state.
- Data collisions must be avoided.
- Setup data should be recreated every time.
Example: Creating Independent Orders
Feature: Independent test data using 'call'
Background:
# Creates a fresh order for every scenario
* def order = call read('utils/create-order.feature')
Scenario: Cancel order
Given path 'orders', order.id, 'cancel'
When method post
Then status 200
Scenario: Update shipping address
Given path 'orders', order.id, 'shipping'
And request { city: 'Cordoba' }
When method put
Then status 200
Here, using call makes sense because each scenario should work with its own independent order.
2. Using callonce (For Shared or Reusable Data)
Use callonce when the returned data can safely be reused across scenarios.
This is commonly used for:
- Authentication tokens.
- Configuration data.
- Master records.
- Reusable setup data.
Example: Reusing an Authentication Token
Feature: Shared authentication using 'callonce'
Background:
# Login executes only once for the feature
* def auth = callonce read('utils/get-auth-token.feature')
* def token = auth.accessToken
Scenario: Get customer profile
Given header Authorization = 'Bearer ' + token
Given path 'customers', 101
When method get
Then status 200
Scenario: Get customer orders
Given header Authorization = 'Bearer ' + token
Given path 'customers', 101, 'orders'
When method get
Then status 200
- Without
callonce, the login request would execute before every scenario. - With
callonce, Karate executes it once and reuses the same result for the rest of the feature.
When to Use Which?
| Situation | Recommended |
|---|---|
| Each scenario needs fresh data | call |
| Data can be shared across scenarios | callonce |
| Creating unique test entities | call |
| Authentication or shared setup | callonce |
| Dynamic or disposable data | call |
| Reusable read-only data | callonce |
Final Thoughts
The difference between call and callonce is simple, but understanding when to use each one can make your Karate tests cleaner and more efficient.
As a general rule:
- Use
callwhen scenarios need fresh or isolated data. - Use
calloncewhen the same result can safely be reused.